using System;
using System.Xml;
using System.Collections.Generic;

namespace AleaClasses
{
	/// <summary>
	/// TNodes defines one node in an Alea graph.
	/// </summary>
	public class TNode: TTrackEdits
	{
		private string fNodeCode;
		private string fDisplayName;
		private string fDescription;
		private string fFileName;
		private TEdges fEdges;
		private TLabels fArrivalLabels;

		private void Constructor(string aNodeCode, string aDisplayName, string aDescription, string aFileName)
		{
			fNodeCode = aNodeCode;
			fDisplayName = aDisplayName;
			fDescription = aDescription;
			fFileName = aFileName;
			fEdges = new TEdges();
			fArrivalLabels = new TLabels();
		}

		public TNode(string aNodeCode, string aDisplayName, string aDescription, string aFileName)
		{
			Constructor(aNodeCode, aDisplayName, aDescription, aFileName);
		}

		public TNode(string aDisplayName, string aDescription, string aFileName)
		{
			Constructor(System.Guid.NewGuid().ToString(), aDisplayName, aDescription, aFileName);
			SetNeedsSave();
		}

		public TNode(XmlElement aNodeElem)
		{
			string lNodeCode;
			string lDisplayName;
			string lDescription;
			string lFileName;

			XmlElement lValueElem = null;
			
			lValueElem = aNodeElem.SelectSingleNode("NodeCode") as XmlElement;
			lNodeCode = Convert.ToString(lValueElem.InnerText);

			lValueElem = aNodeElem.SelectSingleNode("DisplayName") as XmlElement;
			lDisplayName = Convert.ToString(lValueElem.InnerText);

			lValueElem = aNodeElem.SelectSingleNode("Description") as XmlElement;
			lDescription = Convert.ToString(lValueElem.InnerText);

			lValueElem = aNodeElem.SelectSingleNode("FileName") as XmlElement;
			lFileName = Convert.ToString(lValueElem.InnerText);

			Constructor(lNodeCode, lDisplayName, lDescription, lFileName);
		}

		public XmlElement SaveToXml(XmlDocument aDoc)
		{
			XmlElement retval = null;
			XmlElement elem = null;

			retval = aDoc.CreateElement("Node");

			elem = aDoc.CreateElement("NodeCode");
			elem.InnerText = this.NodeCode;
			retval.AppendChild(elem);

			elem = aDoc.CreateElement("DisplayName");
			elem.InnerText = this.DisplayName;
			retval.AppendChild(elem);

			elem = aDoc.CreateElement("Description");
			elem.InnerText = this.Description;
			retval.AppendChild(elem);

			elem = aDoc.CreateElement("FileName");
			elem.InnerText = this.FileName;
			retval.AppendChild(elem);

			// Now save the edges
			if (Edges != null)
			{
				elem = Edges.SaveToXml(aDoc);
				if (elem != null)
					retval.AppendChild(elem);
			}

			// Now save the arrival labels
			if (ArrivalLabels != null)
			{
				elem = ArrivalLabels.SaveToXml(aDoc);
				if (elem != null)
					retval.AppendChild(elem);
			}

			return retval;
		}


		public string NodeCode
		{
			get
			{
				return fNodeCode;
			}
		}

		public string DisplayName
		{
			get
			{
				return fDisplayName;
			}
			set
			{
				if (!fDisplayName.Equals(value))
				{
					fDisplayName = value;
					SetNeedsSave();
				}
			}
		}

		public string Description
		{
			get
			{
				return fDescription;
			}
			set
			{
				if (!fDescription.Equals(value))
				{
					fDescription = value;
					SetNeedsSave();
				}
			}
		}

		public string FileName
		{
			get
			{
				return fFileName;
			}
			set
			{
				if (!fFileName.Equals(value))
				{
					fFileName = value;
					SetNeedsSave();
				}
			}
		}

		internal void SetEdges(TEdges aEdges, bool aNeedsSave)
		{
			fEdges = aEdges;
			if (aNeedsSave)
				SetNeedsSave();
		}

		public TEdges Edges
		{
			get
			{
				return fEdges;
			}
		}

		internal void SetArrivalLabels(TLabels aArrivalLabels, bool aNeedsSave)
		{
			fArrivalLabels = aArrivalLabels;
			if (aNeedsSave)
				SetNeedsSave();
		}

		public TLabels ArrivalLabels
		{
			get
			{
				return fArrivalLabels;
			}
		}

		protected override bool ChildrenNeedSave()
		{
			return Edges.NeedsSave() || ArrivalLabels.NeedsSave();
		}

		protected override void ClearChildrenNeedsSave()
		{
			Edges.ClearNeedsSave();
			ArrivalLabels.ClearNeedsSave();
		}

		private TNode GetNextNodeStrict(string aLabelCode)
		{
			TNode retval = null;

			foreach(TEdge Edge in Edges)
			{
				if (
					((Edge.Label != null) && (Edge.Label.LabelCode == aLabelCode)) ||
					((Edge.Label == null) && (aLabelCode == null))
					)
				{
					retval = Edge.ToNode;
					break;
				}
			}

			return retval;
		}

		public TNode GetNextNode(List<String> aDriveLabelCodes)
		{
			TNode retval = null;

			foreach(string lDriveLabelCode in aDriveLabelCodes)
			{
				retval = GetNextNodeStrict(lDriveLabelCode);

				if (retval != null)
					break;
			}

			if (retval == null)
			{
				retval = GetNextNodeStrict(null);
			}

			return retval;
		}
	}
}
